/*
 * 代号：凤凰
 * http://www.jphenix.org
 * 2016-06-30
 * V4.0
 */
package com.jphenix.servlet.tm;

import com.jphenix.kernel.baseobject.instanceb.ABase;
import com.jphenix.share.lang.SString;
import com.jphenix.share.tools.Base64;
import com.jphenix.share.util.BaseUtil;
import com.jphenix.standard.beans.IBase;
import com.jphenix.standard.docs.ClassInfo;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 任务数据循环存储VO
 * 
 * 2018-01-25
 * 发现有内存泄漏的情况，超出上限的大量的EleVO，故将类变量都改为public，用来观察内容情况
 * 已经解决因为EleVO数量超出上限导致内存溢出的问题。
 * 
 * @author 马宝刚
 * 2013-2-1 上午9:16:50
 */
@ClassInfo({"2018-01-25 10:09","任务数据循环存储VO"})
public class TaskAroundVO extends ABase {

    
    protected long lastPushTime = 0;      //上次放入信息的时间
    protected int elementCount = 0;		//循环元素个数（信息堆栈深度）
    protected List<EleVO> elementList;		//元素序列 ele:EleVO
    protected int taskPoint = 0;			//元素指针
    protected long intervalTime = 0;		//间隔时间
    protected String code = null;			//任务代码
	
	/**
	 * 任务数据元素VO
	 * @author 马宝刚
	 * 2013-2-1 上午9:18:18
	 */
	protected class EleVO {
		
		protected long ts = 0;							//时间戳
		protected Map<String,?> valueMap = null;		//任务数据
		protected String content = null;              //任务数据字符串（二选一）
		
		
		/**
		 * 构造函数
		 * @author 马宝刚
		 * @param valueMap		任务数据
		 */
		public EleVO(Map<String,?> valueMap) {
			super();
			this.ts = System.currentTimeMillis();
			this.valueMap = valueMap;
		}
		
		
		/**
		 * 构造函数
		 * @author 马宝刚
		 * @param content		任务数据
		 */
		public EleVO(String content) {
			super();
			this.ts = System.currentTimeMillis();
			this.content = content;
		}

		
		/**
		 * 获取任务数据
		 * 马宝刚
		 * 2013-2-1 上午9:23:59
		 * @return 任务数据
		 */
		@SuppressWarnings({ "unchecked", "rawtypes" })
		public Map<String,?> getValueMap() {
			if(valueMap==null) {
				valueMap = new HashMap();
			}
			return valueMap;
		}
		
		/**
		 * 覆盖函数
		 */
		@Override
        public String toString() {
		    return "ts:["+ts+"] value_size:["+(valueMap==null?0:valueMap.size())+"] \n Content:["+content+"]";
		}
	}
	
	/**
	 * 构造函数
	 * @author 马宝刚
	 */
	public TaskAroundVO(IBase parent,String code,long intervalTime,int elementCount) {
		super();
		lastPushTime = System.currentTimeMillis();
		setBase(parent); //设置继承基础类支持的功能
		this.code = code;
		elementList = new ArrayList<EleVO>(elementCount);
		if(intervalTime<1) {
			this.intervalTime = 1000;
		}else {
			this.intervalTime = intervalTime;
		}
		if(elementCount<1) {
			this.elementCount = 10;
		}else {
			this.elementCount = elementCount;
		}
	}
	
	/**
	 * 添加任务
	 * @param content 任务数据字符串
	 * 2016年7月4日
	 * @author MBG
	 */
	public synchronized void addTask(String content) {
	    lastPushTime = System.currentTimeMillis();
		//构建任务容器
		EleVO eVO = new EleVO(content);
		if(elementList.size()>=elementCount) {
			elementList.set(taskPoint++,eVO);
		}else {
			elementList.add(taskPoint++,eVO);
		}
		if(taskPoint>=elementCount) {
			taskPoint = 0;
		}
	}

	/**
	 * 添加任务
	 * 马宝刚
	 * 2013-2-1 上午9:44:39
	 * @param valueMap		任务数据
	 */
	public synchronized void addTask(Map<String,?> valueMap) {
	    lastPushTime = System.currentTimeMillis();
		//构建任务容器
		EleVO eVO = new EleVO(valueMap);
		if(elementList.size()>=elementCount) {
			elementList.set(taskPoint++,eVO);
		}else {
			elementList.add(taskPoint++,eVO);
		}
		if(taskPoint>=elementCount) {
			taskPoint = 0;
		}
	}
	
	/**
	 * 获取任务
	 * 马宝刚
	 * 2013-2-1 上午9:47:41
	 * @param ts 时间戳
	 * @param xml 是否返回xml格式
	 * @return js信息值 _taskInfo = {_ts:时间戳,'参数主键'='参数值'}
	 */
	public String getTask(long ts,boolean xml) {
	    //符合条件的信息序列
		List<EleVO> voList = new ArrayList<EleVO>();
		//先保存下来元素总大小，防止在以下处理过程中，该值发生变化
		int eleSize = elementList.size();
		if(ts<1) {
			ts = System.currentTimeMillis();
		}else if(elementList.size()>0){
			ts++; //加1毫秒，避免获取到上一次记录
			if(elementCount>eleSize) {
				//还没有进行循环存储
				//获取最后一个元素
				EleVO eVO;
				for(int i=0;i<eleSize;i++) {
					eVO = elementList.get(i);
					if(eVO==null) {
						continue;
					}
					if(eVO.ts>=ts) {
						ts = eVO.ts;
						voList.add(eVO);
					}
				}
			}else {
				int thisPoint = taskPoint; //当前循环指针
				boolean isFirst = true;	//是否首次循环
				int around = 0; //周期指针
				boolean inData = false; //是否获取到数据
				while(isFirst || (thisPoint!=taskPoint)) {
					isFirst = false;
					around++;
					if(around>elementCount) {
						break;
					}
					if(thisPoint>=elementCount) {
						thisPoint = 0;
					}
					//获取最后一个元素
					EleVO eVO = elementList.get(thisPoint++);
					if(eVO.ts>=ts) {
						inData = true;
						voList.add(eVO);
						ts = eVO.ts;
					}else {
						if(inData) {
							break;
						}
					}
				}
			}
		}
		//构建返回值
		StringBuffer reSbf = new StringBuffer();
		if(voList.size()<1) {
			ts = System.currentTimeMillis();
		}
		if(xml) {
			reSbf
				.append("<task_info><status>1</status><ts>")
				.append(ts)
				.append("</ts>");
			for(EleVO ele:voList) {
				reSbf.append(outVO(ele,true));
			}
			reSbf.append("</task_info>");
		}else {
			reSbf
				.append("var _taskInfo = {'status','1','_ts':'")
				.append(ts)
				.append("','_intervaltime':'")
				.append(intervalTime)
				.append("','element':[");
			boolean noFirst = false; //是否不是首次循环
			for(EleVO ele:voList) {
				if(noFirst) {
					reSbf.append(",");
				}else {
					noFirst = true;
				}
				reSbf.append(outVO(ele,false));
			}
			reSbf.append("]}");
		}
		return reSbf.toString();
	}
	
	
	/**
	 * 输出信息元素
	 * @param ele 信息元素
	 * @param xml 是否为xml格式
	 * @return 信息元素字符串
	 * 2016年7月4日
	 * @author MBG
	 */
	public String outVO(EleVO ele,boolean xml) {
		if(ele.content!=null) {
			if(xml) {
				//不采用<![CDATA["+ele.content+"]]>这种格式了，因为在js中照样解析报错
				return "<content>"+Base64.base64Encode(ele.content,"UTF-8")+"</content>";
			}else {
				return "'"+Base64.base64Encode(ele.content,"UTF-8")+"'";
			}
		}
		//构建返回值
		StringBuffer reSbf = new StringBuffer();
		//参数值容器 
		Map<String,?> valueMap = ele.getValueMap();
		//参数主键序列
		List<String> keyList  = BaseUtil.getMapKeyList(valueMap);
		String key; //参数主键
		if(xml) {
			reSbf.append("<element>");
		}else {
			reSbf.append("{");
		}
		boolean noFirst = false; //是否不是首次循环
		for(int i=0;i<keyList.size();i++) {
			key = SString.valueOf(keyList.get(i));
			if(xml) {
				reSbf
					.append("<key name=\"")
					.append(key)
					.append("\"><![CDATA[")
					.append(SString.valueOf(valueMap.get(key)))
					.append("]]></key>");
			}else {
				if(noFirst) {
					reSbf.append(",");
				}else {
					noFirst = true;
				}
				reSbf
					.append("'")
					.append(key)
					.append("':'")
					.append(BaseUtil.swapString(SString.valueOf(valueMap.get(key)),"'","\\'"))
					.append("'");
			}
		}
		if(xml) {
			reSbf.append("</element>");
		}else {
			reSbf.append("}");
		}
		return reSbf.toString();
	}
	
	
	/**
	 * 覆盖方法
	 */
	@Override
    public String toString() {
	    //构造返回值
	    StringBuffer reSbf = new StringBuffer();
	    reSbf
	        .append("code:[")
	        .append(code)
	        .append("] lastPushTime:[")
	        .append(lastPushTime)
	        .append("] taskPoint:[")
	        .append(taskPoint)
	        .append("] elementCount:[")
	        .append(elementCount)
	        .append("] elementSize:[")
	        .append(elementList.size())
	        .append("]");
	    //不现实详细内容，因为如果元素量过大，会导致输出过多内容
	    return reSbf.toString();
	}
}
